package com.geneqiao.jdbc.pool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

import org.apache.log4j.Logger;

public class JDBCPool
{
	// 日志
	private static final Logger logger = Logger.getLogger(JDBCPool.class);
	private final String url;
	private final String username;
	private final String password;
	private final int maxConn;
	private final int initConn;
	private final BlockingQueue<JDBCConn> connMap;

	private static int used = 0;
	private static int free = 0;

	public JDBCPool(Properties prop) throws SQLException, ClassNotFoundException
	{
		url = prop.getProperty("datasource.url");
		username = prop.getProperty("datasource.username");
		password = prop.getProperty("datasource.password");
		maxConn = Integer.valueOf(prop.getProperty("datasource.maxActive", "16"));
		initConn = Integer.valueOf(prop.getProperty("datasource.maxIdle", "4"));
		connMap = new ArrayBlockingQueue<>(initConn);

		// 加载mysq驱动
		Class.forName(prop.getProperty("datasource.driverClassName"));
		for (int i = 0; i < initConn; i++)
		{
			if (connMap.offer(newConnection()))
			{
				free++;
			}
		}
		logger.debug("----" + getThread() + "-init free -" + free + ",used -" + used);
	}

	public synchronized Connection getConnection() throws InterruptedException, SQLException
	{
		logger.debug("----" + getThread() + "-get s free -" + free + ",used -" + used);
		JDBCConn ss = connMap.poll();
		if (ss == null)
		{
			if (used < maxConn)
				ss = newConnection();
			else
				ss = connMap.take();// 链接大于上限，需等待
		}
		// 如果数据库连接无效
		if (!ss.isValid())
		{
			logger.debug("----" + getThread() + "- invalid");
			if (connMap.size() > 0)
			{
				free--; // 失效连接，空闲数量减少
				return getConnection();
			}
			else
				ss = newConnection();
		}
		used++;
		free--;
		logger.debug("----" + getThread() + "-get e free -" + free + ",used -" + used);
		return ss.getConnection();
	}

	private static String getThread()
	{
		return Thread.currentThread().getName();
	}

	private JDBCConn newConnection() throws SQLException
	{
		logger.debug("----" + getThread() + "-new");
		return new JDBCConn(DriverManager.getConnection(url, username, password), true);
	}

	public synchronized void colseConnection(Connection conn) throws SQLException
	{
		logger.debug("----" + getThread() + "-set s free -" + free + ",used -" + used);
		JDBCConn jdbcConn = new JDBCConn(conn, false);
		if (connMap.offer(jdbcConn))
		{
			free++;
			used--;
			if ((free + used) < initConn)
			{
				int add = initConn - (free + used);
				int num = 0;
				for (int i = 0; i < add; i++)
				{
					if (connMap.offer(newConnection()))
					{
						free++;
						num++;
					}
				}
				logger.debug("----" + getThread() + "-补充连接" + num);
			}
			logger.debug("----" + getThread() + "-set e free -" + free + ",used -" + used);
		}
		else
		{
			used--;
			jdbcConn.close();
			logger.debug("----" + getThread() + "-offer faild free -" + free + ",used -" + used);
		}
	}

	public void shutdown()
	{
		while (!connMap.isEmpty())
		{
			JDBCConn jdbcConn = connMap.poll();
			if (jdbcConn != null)
			{
				jdbcConn.close();
				free--;
			}
		}
		logger.debug("----shutdown free -" + free + ",used -" + used);
	}
}
